Linux webm002.cluster126.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64
/
home
/
a
/
r
/
i
/
ariannadhf
/
www
/
wp-content
/
plugins
/
post-views-counter
/
includes
/
/home/a/r/i/ariannadhf/www/wp-content/plugins/post-views-counter/includes/class-import.php
<?php // exit if accessed directly if ( ! defined( 'ABSPATH' ) ) exit; /** * Post_Views_Counter_Import class. * * @class Post_Views_Counter_Import */ class Post_Views_Counter_Import { /** * Import providers registry. * * @var array */ private $import_providers = []; private $import_provider_labels = []; private $import_strategies = null; private $default_import_strategy = 'merge'; /** * Whether providers have been initialized. * * @var bool */ private $import_providers_initialized = false; /** * Class constructor. * * @return void */ public function __construct() { // register import providers after translations are available add_action( 'init', [ $this, 'initialize_import_providers' ], 5 ); } /** * Initialize import providers. * * @return void */ public function initialize_import_providers() { if ( $this->import_providers_initialized ) return; $this->register_import_providers(); $this->import_providers_initialized = true; } /** * Register import providers. * * @return void */ private function register_import_providers() { // custom meta key provider (always available) $this->import_providers['custom_meta_key'] = [ 'slug' => 'custom_meta_key', 'label' => __( 'Custom Meta Key', 'post-views-counter' ), 'supports' => [ 'total', 'post_types' ], 'is_available' => '__return_true', 'render' => [ $this, 'render_provider_custom_meta_key' ], 'sanitize' => [ $this, 'sanitize_provider_custom_meta_key' ], 'analyse' => [ $this, 'analyse_provider_custom_meta_key' ], 'import' => [ $this, 'import_provider_custom_meta_key' ] ]; // wp-postviews provider (conditional) $this->import_providers['wp_postviews'] = [ 'slug' => 'wp_postviews', 'label' => 'WP-PostViews', 'supports' => [ 'total', 'post_types' ], 'is_available' => [ $this, 'is_wp_postviews_available' ], 'render' => [ $this, 'render_provider_wp_postviews' ], 'sanitize' => [ $this, 'sanitize_provider_wp_postviews' ], 'analyse' => [ $this, 'analyse_provider_wp_postviews' ], 'import' => [ $this, 'import_provider_wp_postviews' ] ]; // statify provider (conditional) $this->import_providers['statify'] = [ 'slug' => 'statify', 'label' => 'Statify', 'supports' => [ 'total', 'yearly', 'monthly', 'weekly', 'daily', 'post_types', 'taxonomies', 'authors', 'other_pages' ], 'is_available' => [ $this, 'is_statify_available' ], 'render' => [ $this, 'render_provider_statify' ], 'sanitize' => [ $this, 'sanitize_provider_statify' ], 'analyse' => [ $this, 'analyse_provider_statify' ], 'import' => [ $this, 'import_provider_statify' ] ]; // page views count provider (conditional) $this->import_providers['page_views_count'] = [ 'slug' => 'page_views_count', 'label' => 'Page Views Count', 'supports' => [ 'total', 'yearly', 'monthly', 'weekly', 'daily', 'post_types' ], 'is_available' => [ $this, 'is_page_views_count_available' ], 'render' => [ $this, 'render_provider_page_views_count' ], 'sanitize' => [ $this, 'sanitize_provider_page_views_count' ], 'analyse' => [ $this, 'analyse_provider_page_views_count' ], 'import' => [ $this, 'import_provider_page_views_count' ] ]; // allow extensions to register additional providers without overriding core ones $additional_providers = apply_filters( 'pvc_import_providers', [] ); if ( is_array( $additional_providers ) ) { foreach ( $additional_providers as $slug => $provider ) { if ( ! is_string( $slug ) || $slug === '' || isset( $this->import_providers[ $slug ] ) ) { continue; } $this->import_providers[ $slug ] = $provider; } } // ensure third-party providers have default supports foreach ( $this->import_providers as $slug => $provider ) { if ( ! isset( $provider['supports'] ) || ! is_array( $provider['supports'] ) ) { $this->import_providers[ $slug ]['supports'] = [ 'total', 'post_types' ]; } } foreach ( $this->import_providers as $slug => $provider ) { $this->import_provider_labels[ $slug ] = isset( $provider['label'] ) ? $provider['label'] : $slug; } } /** * Ensure import providers are loaded. * * @return void */ private function ensure_import_providers_loaded() { if ( ! $this->import_providers_initialized && did_action( 'init' ) ) $this->initialize_import_providers(); } /** * Get all import providers. * * @return array */ public function get_all_providers() { $this->ensure_import_providers_loaded(); return $this->import_providers; } /** * Get available import providers. * * @return array */ public function get_available_providers() { $this->ensure_import_providers_loaded(); $available = []; foreach ( $this->import_providers as $slug => $provider ) { if ( is_callable( $provider['is_available'] ) && call_user_func( $provider['is_available'] ) ) { $available[$slug] = $provider; } } return $available; } /** * Get a specific provider. * * @param string $slug * @return array|null */ public function get_provider( $slug ) { $this->ensure_import_providers_loaded(); return isset( $this->import_providers[$slug] ) ? $this->import_providers[$slug] : null; } /** * Get supports for a specific provider. * * @param string $slug * @return array */ public function get_provider_supports( $slug ) { $provider = $this->get_provider( $slug ); $supports = $provider && isset( $provider['supports'] ) ? $provider['supports'] : []; return apply_filters( 'pvc_import_provider_supports', $supports, $slug ); } /** * Get registered import strategies. * * @return array */ public function get_import_strategies() { if ( $this->import_strategies === null ) { $this->import_strategies = [ 'override' => [ 'label' => __( 'Override existing views', 'post-views-counter' ), 'description' => __( 'Replace stored counts with the imported values.', 'post-views-counter' ), 'pro_only' => false, ], 'merge' => [ 'label' => __( 'Merge with existing views', 'post-views-counter' ), 'description' => __( 'Add imported counts on top of the existing values.', 'post-views-counter' ), 'pro_only' => false, ], 'skip_existing' => [ 'label' => __( 'Skip Existing', 'post-views-counter' ), 'description' => __( 'Only import data when the target record does not exist yet.', 'post-views-counter' ), 'pro_only' => true, ], 'keep_higher_count' => [ 'label' => __( 'Keep Higher Count', 'post-views-counter' ), 'description' => __( 'Keep whichever value is higher when comparing imported and stored counts.', 'post-views-counter' ), 'pro_only' => true, ], 'fill_empty_only' => [ 'label' => __( 'Fill Empty Counts', 'post-views-counter' ), 'description' => __( 'Only import data for posts or periods that currently store zero views.', 'post-views-counter' ), 'pro_only' => true, ], ]; /** * Filter the available import strategies. * * @since 1.5.10 * * @param array $strategies Strategy definitions. * @param Post_Views_Counter_Import $importer Import handler instance. */ $this->import_strategies = apply_filters( 'pvc_import_strategies', $this->import_strategies, $this ); } return $this->import_strategies; } /** * Get default import strategy. * * @return string */ public function get_default_strategy() { return $this->default_import_strategy; } /** * Normalize import strategy against current availability. * * @param string $strategy * @return string */ public function normalize_strategy( $strategy ) { $strategy = sanitize_key( $strategy ); if ( $this->is_strategy_enabled( $strategy ) ) { return $strategy; } return $this->get_default_strategy(); } /** * Check if a strategy can be used in the current environment. * * @param string $strategy * @return bool */ public function is_strategy_enabled( $strategy ) { $strategy = sanitize_key( $strategy ); $definition = $this->get_strategy_definition( $strategy ); if ( $definition === null ) { return false; } if ( ! empty( $definition['pro_only'] ) && ! $this->is_pro_active() ) { return false; } return true; } /** * Get strategy definition. * * @param string $strategy * @return array|null */ private function get_strategy_definition( $strategy ) { $strategy = sanitize_key( $strategy ); $strategies = $this->get_import_strategies(); return isset( $strategies[ $strategy ] ) ? $strategies[ $strategy ] : null; } /** * Check whether the related class is available. * * @return bool */ private function is_pro_active() { return class_exists( 'Post_Views_Counter_Pro' ); } /** * Generate a description for a provider based on its supports. * * @param array $supports * @return string */ private function generate_provider_description( $supports ) { $parts = []; // Date periods $dates = []; if ( in_array( 'total', $supports, true ) ) { $dates[] = _x( 'total', 'view_counts', 'post-views-counter' ); } if ( in_array( 'yearly', $supports, true ) ) { $dates[] = _x( 'yearly', 'view_counts', 'post-views-counter' ); } if ( in_array( 'monthly', $supports, true ) ) { $dates[] = _x( 'monthly', 'view_counts', 'post-views-counter' ); } if ( in_array( 'weekly', $supports, true ) ) { $dates[] = _x( 'weekly', 'view_counts', 'post-views-counter' ); } if ( in_array( 'daily', $supports, true ) ) { $dates[] = _x( 'daily', 'view_counts', 'post-views-counter' ); } // Content types $content_labels = [ 'post_types' => _x( 'post types', 'view_counts', 'post-views-counter' ), 'taxonomies' => _x( 'taxonomies', 'view_counts', 'post-views-counter' ), 'authors' => _x( 'author archives', 'view_counts', 'post-views-counter' ), 'other_pages' => _x( 'other pages', 'view_counts', 'post-views-counter' ), 'traffic_sources' => _x( 'traffic sources', 'view_counts', 'post-views-counter' ) ]; $content = []; $pro_only_keys = [ 'taxonomies', 'authors', 'other_pages', 'traffic_sources' ]; $content_keys = [ 'post_types' ]; foreach ( $content_keys as $key ) { if ( in_array( $key, $supports, true ) && isset( $content_labels[ $key ] ) ) { $content[] = $content_labels[ $key ]; } } if ( ! empty( $dates ) && ! empty( $content ) ) { $parts[] = sprintf( __( 'Imports %s view counts for %s', 'post-views-counter' ), $this->format_list( $dates ), $this->format_list( $content ) ); } elseif ( ! empty( $dates ) ) { $parts[] = sprintf( __( 'Imports %s view counts', 'post-views-counter' ), $this->format_list( $dates ) ); } $pro_content = []; foreach ( $pro_only_keys as $key ) { if ( in_array( $key, $supports, true ) && isset( $content_labels[ $key ] ) ) { $pro_content[] = $content_labels[ $key ]; } } if ( ! empty( $pro_content ) ) { $parts[] = sprintf( __( 'PVC Pro additionally imports %s view counts', 'post-views-counter' ), $this->format_list( $pro_content ) ); } if ( empty( $parts ) ) { return ''; } return implode( '. ', $parts ) . '.'; } /** * Format a list of items into a human-readable string. * * @param array $items * @return string */ private function format_list( $items ) { if ( count( $items ) === 1 ) { return $items[0]; } $last = array_pop( $items ); return implode( ', ', $items ) . ' ' . _x( 'and', 'view_counts', 'post-views-counter' ) . ' ' . $last; } /** * Handle manual import/analyse action. * * @param array $request * @return array */ public function handle_manual_action( $request ) { // get provider selection $provider_slug = isset( $request['pvc_import_provider'] ) ? sanitize_key( $request['pvc_import_provider'] ) : 'custom_meta_key'; // get import strategy and validate $strategy = isset( $request['pvc_import_strategy'] ) ? $this->normalize_strategy( $request['pvc_import_strategy'] ) : $this->get_default_strategy(); // get provider inputs $provider_inputs = isset( $request['pvc_import_provider_inputs'] ) ? $request['pvc_import_provider_inputs'] : []; // get available providers $providers = $this->get_available_providers(); // validate provider exists if ( ! isset( $providers[$provider_slug] ) ) { return [ 'success' => false, 'message' => __( 'Invalid import provider selected.', 'post-views-counter' ), 'type' => 'error' ]; } $provider = $providers[$provider_slug]; // sanitize provider inputs $sanitized_inputs = []; if ( is_callable( $provider['sanitize'] ) ) { $sanitized_inputs = call_user_func( $provider['sanitize'], $provider_inputs ); } // get main instance $pvc = Post_Views_Counter(); // preserve existing provider settings, only update current provider $existing_settings = isset( $pvc->options['other']['import_provider_settings'] ) ? $pvc->options['other']['import_provider_settings'] : []; $provider_settings = array_merge( $existing_settings, [ 'provider' => $provider_slug, 'strategy' => $strategy, $provider_slug => $sanitized_inputs ] ); $result = []; // handle analyse if ( isset( $request['post_views_counter_analyse_views'] ) ) { if ( is_callable( $provider['analyse'] ) ) { $analyse_result = call_user_func( $provider['analyse'], $sanitized_inputs ); if ( isset( $analyse_result['message'] ) ) { $result = [ 'success' => true, 'message' => $analyse_result['message'], 'type' => 'updated', 'provider_settings' => $provider_settings ]; } } // handle import } elseif ( isset( $request['post_views_counter_import_views'] ) ) { if ( is_callable( $provider['import'] ) ) { $import_result = call_user_func( $provider['import'], $sanitized_inputs, $strategy ); if ( isset( $import_result['success'] ) && $import_result['success'] ) { $result = [ 'success' => true, 'message' => $import_result['message'], 'type' => 'updated', 'provider_settings' => $provider_settings ]; } else if ( isset( $import_result['message'] ) ) { $result = [ 'success' => false, 'message' => $import_result['message'], 'type' => isset( $import_result['success'] ) && ! $import_result['success'] ? 'updated' : 'error', 'provider_settings' => $provider_settings ]; } } } return $result; } /** * Prepare provider settings from request. * * @param array $request * @return array */ public function prepare_provider_settings_from_request( $request ) { // get existing provider settings or initialize $pvc = Post_Views_Counter(); $existing_settings = isset( $pvc->options['other']['import_provider_settings'] ) ? $pvc->options['other']['import_provider_settings'] : []; // check if provider inputs were submitted if ( isset( $request['pvc_import_provider'], $request['pvc_import_provider_inputs'], $request['pvc_import_strategy'] ) ) { $provider_slug = sanitize_key( $request['pvc_import_provider'] ); $provider_inputs = $request['pvc_import_provider_inputs']; $strategy = $this->normalize_strategy( $request['pvc_import_strategy'] ); // get available providers $providers = $this->get_available_providers(); // validate provider exists if ( isset( $providers[$provider_slug] ) ) { $provider = $providers[$provider_slug]; // sanitize provider inputs $sanitized_inputs = []; if ( is_callable( $provider['sanitize'] ) ) { $sanitized_inputs = call_user_func( $provider['sanitize'], $provider_inputs ); } // update provider settings return array_merge( $existing_settings, [ 'provider' => $provider_slug, 'strategy' => $strategy, $provider_slug => $sanitized_inputs ] ); } } // preserve existing settings if not changed return $existing_settings; } /** * Check if WP-PostViews is available. * * @return bool */ public function is_wp_postviews_available() { return function_exists( 'the_views' ); } /** * Render custom meta key provider fields. * * @return string */ public function render_provider_custom_meta_key() { // get main instance $pvc = Post_Views_Counter(); // get saved meta key or default $meta_key = isset( $pvc->options['other']['import_provider_settings']['custom_meta_key']['meta_key'] ) ? $pvc->options['other']['import_provider_settings']['custom_meta_key']['meta_key'] : 'views'; // get provider $provider = $this->get_provider( 'custom_meta_key' ); // generate description $description = $this->generate_provider_description( $provider['supports'] ) . ' ' . esc_html__( 'Enter the meta key from which the views data is to be retrieved during import.', 'post-views-counter' ); $html = ' <div class="pvc-provider-fields"> <input type="text" id="pvc_import_meta_key" class="regular-text" name="pvc_import_provider_inputs[meta_key]" value="' . esc_attr( $meta_key ) . '" /> <p class="description">' . $description . '</p> </div>'; return $html; } /** * Sanitize custom meta key provider inputs. * * @param array $inputs * @return array */ public function sanitize_provider_custom_meta_key( $inputs ) { $sanitized = []; if ( isset( $inputs['meta_key'] ) ) { $sanitized['meta_key'] = sanitize_key( $inputs['meta_key'] ); } return $sanitized; } /** * Analyse custom meta key provider. * * @global object $wpdb * * @param array $inputs * @return array */ public function analyse_provider_custom_meta_key( $inputs ) { global $wpdb; $meta_key = isset( $inputs['meta_key'] ) ? sanitize_key( $inputs['meta_key'] ) : 'views'; // get views data $views = $wpdb->get_results( $wpdb->prepare( "SELECT post_id, meta_value FROM " . $wpdb->postmeta . " WHERE meta_key = %s AND meta_value > 0", $meta_key ), ARRAY_A ); if ( empty( $views ) ) { return [ 'count' => 0, 'message' => sprintf( __( 'No valid views data found for %s.', 'post-views-counter' ), sprintf( __( 'meta key: %s', 'post-views-counter' ), esc_html( $meta_key ) ) ) ]; } // calculate total views $total_views = 0; foreach ( $views as $view ) { $total_views += (int) $view['meta_value']; } $stats = [ 'total_views' => $total_views, 'posts_processed' => count( $views ), 'source' => $this->get_provider_label( 'custom_meta_key' ), 'additional_info' => sprintf( __( 'Meta key "%s".', 'post-views-counter' ), esc_html( $meta_key ) ) ]; return [ 'count' => count( $views ), 'message' => $this->generate_import_message( $stats, 'analyze' ) ]; } /** * Import custom meta key provider. * * @global object $wpdb * * @param array $inputs * @param string $strategy * @return array */ public function import_provider_custom_meta_key( $inputs, $strategy ) { global $wpdb; $meta_key = isset( $inputs['meta_key'] ) ? sanitize_key( $inputs['meta_key'] ) : 'views'; // get views $views = $wpdb->get_results( $wpdb->prepare( "SELECT post_id, meta_value FROM " . $wpdb->postmeta . " WHERE meta_key = %s AND meta_value > 0", $meta_key ), ARRAY_A, 0 ); if ( empty( $views ) ) { return [ 'success' => false, 'message' => __( 'No valid post data found to import.', 'post-views-counter' ) ]; } $sql = []; $totals_map = []; $total_views = 0; foreach ( $views as $view ) { $post_id = (int) $view['post_id']; $count = (int) $view['meta_value']; $sql[] = $wpdb->prepare( "(%d, 4, 'total', %d)", $post_id, $count ); $total_views += $count; $totals_map[ $post_id ] = ( isset( $totals_map[ $post_id ] ) ? $totals_map[ $post_id ] : 0 ) + $count; } $this->execute_provider_insert_query( $sql, $strategy, 'custom_meta_key' ); $stats = [ 'total_views' => $total_views, 'posts_processed' => count( $totals_map ), 'source' => $this->get_provider_label( 'custom_meta_key' ), 'additional_info' => sprintf( __( 'Meta key "%s".', 'post-views-counter' ), esc_html( $meta_key ) ) ]; $this->apply_skip_statistics( $stats, $totals_map, $strategy ); return [ 'success' => true, 'message' => $this->generate_import_message( $stats ) ]; } /** * Render WP-PostViews provider fields. * * @return string */ public function render_provider_wp_postviews() { // get provider $provider = $this->get_provider( 'wp_postviews' ); // generate description $description = $this->generate_provider_description( $provider['supports'] ); $html = ' <div class="pvc-provider-fields"> <p class="description">' . $description . '</p> </div>'; return $html; } /** * Sanitize WP-PostViews provider inputs. * * @param array $inputs * @return array */ public function sanitize_provider_wp_postviews( $inputs ) { // no inputs needed for WP-PostViews return []; } /** * Analyse WP-PostViews provider. * * @global object $wpdb * * @param array $inputs * @return array */ public function analyse_provider_wp_postviews( $inputs ) { global $wpdb; // wp-postviews uses 'views' meta key $views = $wpdb->get_results( "SELECT post_id, meta_value FROM " . $wpdb->postmeta . " WHERE meta_key = 'views' AND meta_value > 0", ARRAY_A ); if ( empty( $views ) ) { return [ 'count' => 0, 'message' => sprintf( __( 'No valid views data found for %s.', 'post-views-counter' ), 'WP-PostViews' ) ]; } // calculate total views $total_views = 0; foreach ( $views as $view ) { $total_views += (int) $view['meta_value']; } $stats = [ 'total_views' => $total_views, 'posts_processed' => count( $views ), 'source' => $this->get_provider_label( 'wp_postviews' ) ]; return [ 'count' => count( $views ), 'message' => $this->generate_import_message( $stats, 'analyze' ) ]; } /** * Import WP-PostViews provider. * * @global object $wpdb * * @param array $inputs * @param string $strategy * @return array */ public function import_provider_wp_postviews( $inputs, $strategy ) { global $wpdb; // wp-postviews uses 'views' meta key $views = $wpdb->get_results( "SELECT post_id, meta_value FROM " . $wpdb->postmeta . " WHERE meta_key = 'views' AND meta_value > 0", ARRAY_A, 0 ); if ( empty( $views ) ) { return [ 'success' => false, 'message' => __( 'No valid post data found to import.', 'post-views-counter' ) ]; } $sql = []; $totals_map = []; $total_views = 0; foreach ( $views as $view ) { $post_id = (int) $view['post_id']; $count = (int) $view['meta_value']; $sql[] = $wpdb->prepare( "(%d, 4, 'total', %d)", $post_id, $count ); $total_views += $count; $totals_map[ $post_id ] = ( isset( $totals_map[ $post_id ] ) ? $totals_map[ $post_id ] : 0 ) + $count; } $this->execute_provider_insert_query( $sql, $strategy, 'wp_postviews' ); $stats = [ 'total_views' => $total_views, 'posts_processed' => count( $totals_map ), 'source' => $this->get_provider_label( 'wp_postviews' ) ]; $this->apply_skip_statistics( $stats, $totals_map, $strategy ); return [ 'success' => true, 'message' => $this->generate_import_message( $stats ) ]; } /** * Check if Statify is available. * * @return bool */ public function is_statify_available() { global $wpdb; $table = esc_sql( isset( $wpdb->statify ) ? $wpdb->statify : $wpdb->prefix . 'statify' ); return class_exists( 'Statify' ) && $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table ) ) === $table; } /** * Render Statify provider fields. * * @return string */ public function render_provider_statify() { // get provider $provider = $this->get_provider( 'statify' ); // generate description $description = $this->generate_provider_description( $provider['supports'] ); $html = ' <div class="pvc-provider-fields"> <p class="description">' . $description . '</p> </div>'; return $html; } /** * Sanitize Statify provider inputs. * * @param array $inputs * @return array */ public function sanitize_provider_statify( $inputs ) { // no inputs needed for Statify return []; } /** * Analyse Statify provider. * * @global object $wpdb * * @param array $inputs * @return array */ public function analyse_provider_statify( $inputs ) { global $wpdb; $table = esc_sql( isset( $wpdb->statify ) ? $wpdb->statify : $wpdb->prefix . 'statify' ); $pvc_settings = Post_Views_Counter()->options['general']; $use_gmt = $pvc_settings['count_time'] === 'gmt'; $tracked_post_types = array_map( 'sanitize_key', (array) $pvc_settings['post_types_count'] ); // get aggregated data to analyze $rows = $wpdb->get_results( "SELECT target, created, COUNT(*) AS views FROM `{$table}` GROUP BY target, created", ARRAY_A ); if ( empty( $rows ) ) { return [ 'count' => 0, 'message' => sprintf( __( 'No valid views data found for %s.', 'post-views-counter' ), 'Statify' ) ]; } $stats = []; $skipped_targets = []; $total_views = 0; $period_counts = [ 'daily' => 0, 'weekly' => 0, 'monthly' => 0, 'yearly' => 0 ]; foreach ( $rows as $row ) { $content = $this->map_target_to_content( $row['target'], $tracked_post_types, 'statify' ); $post_id = isset( $content['content_id'] ) ? (int) $content['content_id'] : 0; if ( ! $post_id ) { $skipped_targets[] = $row['target']; continue; } $ts = strtotime( $row['created'] ); $period_keys = $this->get_period_keys_from_timestamp( $ts, $use_gmt ); if ( isset( $content['content_type'] ) && $content['content_type'] !== 'post' ) { /** * Allow to capture provider rows that map to non-post content. * * Returning true from this filter stops default processing for the row. * * @since 1.5.10 * * @param bool $handled Whether the row was fully processed. * @param array $context Contextual data about the provider row. * @param Post_Views_Counter_Import $importer Import handler instance. */ $handled = apply_filters( 'pvc_import_handle_non_post_row', false, [ 'mode' => 'analyze', 'source' => 'statify', 'row' => $row, 'content' => $content, 'period_keys' => $period_keys, 'timestamp' => $ts, 'use_gmt' => $use_gmt ], $this ); if ( $handled ) continue; $skipped_targets[] = $row['target']; continue; } $day_key = $period_keys['day']; $week_key = $period_keys['week']; $month_key = $period_keys['month']; $year_key = $period_keys['year']; if ( ! isset( $stats[$post_id] ) ) { $stats[$post_id] = [ 'daily' => [], 'weekly' => [], 'monthly' => [], 'yearly' => [], 'total' => 0 ]; } if ( ! isset( $stats[$post_id]['daily'][$day_key] ) ) { $period_counts['daily']++; } if ( ! isset( $stats[$post_id]['weekly'][$week_key] ) ) { $period_counts['weekly']++; } if ( ! isset( $stats[$post_id]['monthly'][$month_key] ) ) { $period_counts['monthly']++; } if ( ! isset( $stats[$post_id]['yearly'][$year_key] ) ) { $period_counts['yearly']++; } $stats[$post_id]['daily'][$day_key] = ( $stats[$post_id]['daily'][$day_key] ?? 0 ) + $row['views']; $stats[$post_id]['weekly'][$week_key] = ( $stats[$post_id]['weekly'][$week_key] ?? 0 ) + $row['views']; $stats[$post_id]['monthly'][$month_key] = ( $stats[$post_id]['monthly'][$month_key] ?? 0 ) + $row['views']; $stats[$post_id]['yearly'][$year_key] = ( $stats[$post_id]['yearly'][$year_key] ?? 0 ) + $row['views']; $stats[$post_id]['total'] += $row['views']; $total_views += $row['views']; } // prepare statistics for message generation $provider_slug = 'statify'; $provider_label = isset( $this->import_provider_labels[ $provider_slug ] ) ? $this->import_provider_labels[ $provider_slug ] : $provider_slug; $message_stats = [ 'total_views' => $total_views, 'posts_processed' => count( $stats ), 'periods' => $period_counts, 'source' => $provider_label ]; // add skipped URLs info if any if ( ! empty( $skipped_targets ) ) { $unique_skipped = array_unique( $skipped_targets ); $message_stats['additional_info'] = sprintf( __( 'Would skip %s non-post URLs.', 'post-views-counter' ), number_format_i18n( count( $unique_skipped ) ) ); } /** * Allow to adjust provider analysis statistics before displaying the message. * * @since 1.5.10 * @since 1.5.11 Provider parameter moved to the third position. * * @param array $message_stats Prepared statistics for the UI. * @param array $context Additional context such as mode/source. */ $message_stats = apply_filters( 'pvc_import_message_stats', $message_stats, [ 'mode' => 'analyze', 'source' => 'statify' ] ); return [ 'count' => $total_views, 'message' => $this->generate_import_message( $message_stats, 'analyze' ) ]; } /** * Import Statify provider. * * @global object $wpdb * * @param array $inputs * @param string $strategy * @return array */ public function import_provider_statify( $inputs, $strategy ) { global $wpdb; $table = esc_sql( isset( $wpdb->statify ) ? $wpdb->statify : $wpdb->prefix . 'statify' ); $pvc_settings = Post_Views_Counter()->options['general']; $use_gmt = $pvc_settings['count_time'] === 'gmt'; $tracked_post_types = array_map( 'sanitize_key', (array) $pvc_settings['post_types_count'] ); // Fetch aggregated data in chunks $offset = 0; $limit = 1000; // Adjust for memory $stats = []; $skipped_targets = []; while ( true ) { $rows = $wpdb->get_results( $wpdb->prepare( "SELECT target, created, COUNT(*) AS views FROM `{$table}` GROUP BY target, created ORDER BY target, created LIMIT %d OFFSET %d", $limit, $offset ), ARRAY_A ); if ( empty( $rows ) ) break; foreach ( $rows as $row ) { $content = $this->map_target_to_content( $row['target'], $tracked_post_types, 'statify' ); $post_id = isset( $content['content_id'] ) ? (int) $content['content_id'] : 0; if ( ! $post_id ) { $skipped_targets[] = $row['target']; continue; } $ts = strtotime( $row['created'] ); $period_keys = $this->get_period_keys_from_timestamp( $ts, $use_gmt ); if ( isset( $content['content_type'] ) && $content['content_type'] !== 'post' ) { /** This filter is documented above. */ $handled = apply_filters( 'pvc_import_handle_non_post_row', false, [ 'mode' => 'import', 'source' => 'statify', 'row' => $row, 'content' => $content, 'period_keys' => $period_keys, 'timestamp' => $ts, 'use_gmt' => $use_gmt, 'strategy' => $strategy ], $this ); if ( $handled ) continue; $skipped_targets[] = $row['target']; continue; } $day_key = $period_keys['day']; $week_key = $period_keys['week']; $month_key = $period_keys['month']; $year_key = $period_keys['year']; if ( ! isset( $stats[$post_id] ) ) { $stats[$post_id] = [ 'daily' => [], 'weekly' => [], 'monthly' => [], 'yearly' => [], 'total' => 0 ]; } $stats[$post_id]['daily'][$day_key] = ( $stats[$post_id]['daily'][$day_key] ?? 0 ) + $row['views']; $stats[$post_id]['weekly'][$week_key] = ( $stats[$post_id]['weekly'][$week_key] ?? 0 ) + $row['views']; $stats[$post_id]['monthly'][$month_key] = ( $stats[$post_id]['monthly'][$month_key] ?? 0 ) + $row['views']; $stats[$post_id]['yearly'][$year_key] = ( $stats[$post_id]['yearly'][$year_key] ?? 0 ) + $row['views']; $stats[$post_id]['total'] += $row['views']; } $offset += $limit; } // Batch insert and collect statistics $sql_parts = []; $total_views = 0; $posts_processed = 0; $period_counts = [ 'daily' => 0, 'weekly' => 0, 'monthly' => 0, 'yearly' => 0 ]; $totals_map = []; foreach ( $stats as $post_id => $periods ) { $posts_processed++; foreach ( $periods['daily'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 0, %s, %d)", $post_id, $period, $count ); $period_counts['daily']++; } foreach ( $periods['weekly'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 1, %s, %d)", $post_id, $period, $count ); $period_counts['weekly']++; } foreach ( $periods['monthly'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 2, %s, %d)", $post_id, $period, $count ); $period_counts['monthly']++; } foreach ( $periods['yearly'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 3, %s, %d)", $post_id, $period, $count ); $period_counts['yearly']++; } $sql_parts[] = $wpdb->prepare( "(%d, 4, 'total', %d)", $post_id, $periods['total'] ); $total_views += $periods['total']; $totals_map[ $post_id ] = $periods['total']; } if ( empty( $sql_parts ) ) { $debug_message = __( 'No valid post data found to import.', 'post-views-counter' ); // add helpful debug info if ( empty( $tracked_post_types ) ) { $debug_message .= ' ' . __( 'No post types are selected for tracking in settings.', 'post-views-counter' ); } elseif ( ! empty( $skipped_targets ) ) { $unique_skipped = array_unique( $skipped_targets ); $sample_targets = array_slice( $unique_skipped, 0, 5 ); $debug_message .= ' ' . sprintf( __( 'All %s URLs were skipped. Sample URLs: %s', 'post-views-counter' ), number_format_i18n( count( $unique_skipped ) ), implode( ', ', array_map( 'esc_html', $sample_targets ) ) ); } return [ 'success' => false, 'message' => $debug_message ]; } $this->execute_provider_insert_query( $sql_parts, $strategy, 'statify' ); /** * Fires after a provider's post rows have been inserted. * * @since 1.5.10 * * @param array $context { * @type string $strategy Selected merge strategy. * @type string $source Provider slug (statify). * @type bool $use_gmt Whether GMT dates were used. * } */ do_action( 'pvc_import_after_provider', [ 'strategy' => $strategy, 'source' => 'statify', 'use_gmt' => $use_gmt ] ); $this->flush_pvc_caches(); // prepare statistics for message generation $provider_slug = 'statify'; $provider_label = isset( $this->import_provider_labels[ $provider_slug ] ) ? $this->import_provider_labels[ $provider_slug ] : $provider_slug; $message_stats = [ 'total_views' => $total_views, 'posts_processed' => $posts_processed, 'periods' => $period_counts, 'source' => $provider_label ]; // add skipped URLs info if any if ( ! empty( $skipped_targets ) ) { $unique_skipped = array_unique( $skipped_targets ); $message_stats['additional_info'] = sprintf( __( 'Skipped %s non-post URLs.', 'post-views-counter' ), number_format_i18n( count( $unique_skipped ) ) ); } $this->apply_skip_statistics( $message_stats, $totals_map, $strategy ); /** * Allow to adjust provider import statistics before displaying the message. * * @since 1.5.10 * * @param array $stats Prepared statistics for the UI. * @param array $context Additional context such as mode/source. */ $message_stats = apply_filters( 'pvc_import_message_stats', $message_stats, [ 'mode' => 'import', 'source' => 'statify' ] ); return [ 'success' => true, 'message' => $this->generate_import_message( $message_stats ) ]; } /** * Check if Page Views Count is available. * * @return bool */ public function is_page_views_count_available() { global $wpdb; $table_total = $wpdb->prefix . 'pvc_total'; $table_daily = $wpdb->prefix . 'pvc_daily'; return $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_total ) ) === $table_total && $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_daily ) ) === $table_daily; } /** * Render Page Views Count provider fields. * * @return string */ public function render_provider_page_views_count() { // get provider $provider = $this->get_provider( 'page_views_count' ); // generate description $description = $this->generate_provider_description( $provider['supports'] ); $html = ' <div class="pvc-provider-fields"> <p class="description">' . $description . '</p> </div>'; return $html; } /** * Sanitize Page Views Count provider inputs. * * @param array $inputs * @return array */ public function sanitize_provider_page_views_count( $inputs ) { // no inputs needed for Page Views Count return []; } /** * Analyse Page Views Count provider. * * @global object $wpdb * * @param array $inputs * @return array */ public function analyse_provider_page_views_count( $inputs ) { global $wpdb; $table_total = $wpdb->prefix . 'pvc_total'; $table_daily = $wpdb->prefix . 'pvc_daily'; $pvc_settings = Post_Views_Counter()->options['general']; $tracked_post_types = array_map( 'sanitize_key', (array) $pvc_settings['post_types_count'] ); $post_types_cache = []; // get total views $totals = $wpdb->get_results( "SELECT postnum, postcount FROM {$table_total}", ARRAY_A ); $total_views = 0; $valid_posts_total = []; foreach ( $totals as $row ) { $post_id = (int) $row['postnum']; if ( ! isset( $post_types_cache[$post_id] ) ) { $post_types_cache[$post_id] = get_post_type( $post_id ); } if ( $post_types_cache[$post_id] && in_array( $post_types_cache[$post_id], $tracked_post_types, true ) ) { $total_views += (int) $row['postcount']; $valid_posts_total[] = $post_id; } } // get daily views $dailies = $wpdb->get_results( "SELECT time, postnum, postcount FROM {$table_daily}", ARRAY_A ); $daily_views = 0; $valid_posts_daily = []; foreach ( $dailies as $row ) { $post_id = (int) $row['postnum']; if ( ! isset( $post_types_cache[$post_id] ) ) { $post_types_cache[$post_id] = get_post_type( $post_id ); } if ( $post_types_cache[$post_id] && in_array( $post_types_cache[$post_id], $tracked_post_types, true ) ) { $daily_views += (int) $row['postcount']; $valid_posts_daily[] = $post_id; } } $posts_processed = count( array_unique( array_merge( $valid_posts_total, $valid_posts_daily ) ) ); $stats = [ 'total_views' => $total_views, 'posts_processed' => $posts_processed, 'source' => $this->get_provider_label( 'page_views_count' ), ]; return [ 'count' => $total_views + $daily_views, 'message' => $this->generate_import_message( $stats, 'analyze' ) ]; } /** * Import Page Views Count provider. * * @global object $wpdb * * @param array $inputs * @param string $strategy * @return array */ public function import_provider_page_views_count( $inputs, $strategy ) { global $wpdb; $table_total = $wpdb->prefix . 'pvc_total'; $table_daily = $wpdb->prefix . 'pvc_daily'; $pvc_settings = Post_Views_Counter()->options['general']; $tracked_post_types = array_map( 'sanitize_key', (array) $pvc_settings['post_types_count'] ); $post_types_cache = []; $results = $wpdb->get_results( "SELECT t.postnum, t.postcount AS total, d.time, d.postcount AS daily_count FROM {$table_total} AS t LEFT JOIN {$table_daily} AS d ON t.postnum = d.postnum ORDER BY t.postnum, d.time", ARRAY_A ); $sql_parts = []; $stats = []; $totals_map = []; $total_views_imported = 0; foreach ( $results as $row ) { $post_id = (int) $row['postnum']; if ( ! isset( $post_types_cache[ $post_id ] ) ) { $post_types_cache[ $post_id ] = get_post_type( $post_id ); } $post_type = $post_types_cache[ $post_id ]; if ( ! $post_type || ! in_array( $post_type, $tracked_post_types, true ) ) { continue; } if ( isset( $row['total'] ) && ! isset( $stats[ $post_id ]['total_imported'] ) ) { $count = (int) $row['total']; $total_views_imported += $count; $sql_parts[] = $wpdb->prepare( "(%d, 4, 'total', %d)", $post_id, $count ); $totals_map[ $post_id ] = $count; $stats[ $post_id ]['total_imported'] = true; } if ( empty( $row['time'] ) ) { continue; } $ts = strtotime( $row['time'] . ' 00:00:00' ); $period_keys = $this->get_period_keys_from_timestamp( $ts, false ); // Use site time as data is in site time if ( ! isset( $stats[ $post_id ] ) ) { $stats[ $post_id ] = [ 'periods' => [ 'daily' => [], 'weekly' => [], 'monthly' => [], 'yearly' => [] ] ]; } $stats[ $post_id ]['periods']['daily'][ $period_keys['day'] ] = ( $stats[ $post_id ]['periods']['daily'][ $period_keys['day'] ] ?? 0 ) + (int) $row['daily_count']; $stats[ $post_id ]['periods']['weekly'][ $period_keys['week'] ] = ( $stats[ $post_id ]['periods']['weekly'][ $period_keys['week'] ] ?? 0 ) + (int) $row['daily_count']; $stats[ $post_id ]['periods']['monthly'][ $period_keys['month'] ] = ( $stats[ $post_id ]['periods']['monthly'][ $period_keys['month'] ] ?? 0 ) + (int) $row['daily_count']; $stats[ $post_id ]['periods']['yearly'][ $period_keys['year'] ] = ( $stats[ $post_id ]['periods']['yearly'][ $period_keys['year'] ] ?? 0 ) + (int) $row['daily_count']; } if ( empty( $sql_parts ) ) { return [ 'success' => false, 'message' => __( 'No valid post data found to import.', 'post-views-counter' ) ]; } $period_counts = [ 'daily' => 0, 'weekly' => 0, 'monthly' => 0, 'yearly' => 0 ]; foreach ( $stats as $post_id => $data ) { foreach ( $data['periods']['daily'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 0, %s, %d)", $post_id, $period, $count ); $period_counts['daily']++; } foreach ( $data['periods']['weekly'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 1, %s, %d)", $post_id, $period, $count ); $period_counts['weekly']++; } foreach ( $data['periods']['monthly'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 2, %s, %d)", $post_id, $period, $count ); $period_counts['monthly']++; } foreach ( $data['periods']['yearly'] as $period => $count ) { $sql_parts[] = $wpdb->prepare( "(%d, 3, %s, %d)", $post_id, $period, $count ); $period_counts['yearly']++; } } $posts_processed = count( array_keys( $stats ) ); $this->execute_provider_insert_query( $sql_parts, $strategy, 'page_views_count' ); do_action( 'pvc_import_after_provider', [ 'strategy' => $strategy, 'source' => 'page_views_count', 'use_gmt' => false ] ); $this->flush_pvc_caches(); $provider_slug = 'page_views_count'; $provider_label = isset( $this->import_provider_labels[ $provider_slug ] ) ? $this->import_provider_labels[ $provider_slug ] : $provider_slug; $message_stats = [ 'total_views' => $total_views_imported, 'posts_processed' => $posts_processed, 'periods' => $period_counts, 'source' => $provider_label ]; $this->apply_skip_statistics( $message_stats, $totals_map, $strategy ); $message_stats = apply_filters( 'pvc_import_message_stats', $message_stats, [ 'mode' => 'import', 'source' => 'page_views_count' ] ); return [ 'success' => true, 'message' => $this->generate_import_message( $message_stats ) ]; } /** * Get SQL clause for the provided strategy. * * @param string $strategy * @param string $provider * @return string */ private function get_strategy_on_duplicate_clause( $strategy, $provider ) { $strategy_key = sanitize_key( $strategy ); $clauses = [ 'override' => 'count = VALUES(count)', 'merge' => 'count = count + VALUES(count)' ]; $clause = isset( $clauses[ $strategy_key ] ) ? $clauses[ $strategy_key ] : $clauses['merge']; /** * Filter the SQL ON DUPLICATE KEY UPDATE clause used during import. * * @since 1.5.10 * * @param string $clause SQL clause for the duplicate key handler. * @param array $context { * @type string $strategy Selected strategy key. * @type string $provider Provider slug. * } * @param Post_Views_Counter_Import $importer Import handler instance. */ return apply_filters( 'pvc_import_strategy_clause', $clause, [ 'strategy' => $strategy_key, 'provider' => $provider ], $this ); } /** * Execute a provider insert query. * * @param array $sql_parts Prepared SQL value tuples. * @param string $strategy Selected strategy. * @param string $provider Provider slug. * @return int|false Number of rows affected by the query or false when skipped. */ private function execute_provider_insert_query( $sql_parts, $strategy, $provider ) { global $wpdb; if ( empty( $sql_parts ) ) { return false; } $on_duplicate = $this->get_strategy_on_duplicate_clause( $strategy, $provider ); $query = "INSERT INTO {$wpdb->prefix}post_views (id, type, period, count) VALUES " . implode( ',', $sql_parts ) . " ON DUPLICATE KEY UPDATE {$on_duplicate}"; /** * Filter the SQL query used when inserting provider data. * * Returning false will skip executing the default query. Extensions can run * their custom SQL before returning false. * * @since 1.5.10 * * @param string|false $query SQL query string or false to skip execution. * @param array $context { * @type string $strategy Selected strategy. * @type string $provider Provider slug. * @type array $sql_parts Prepared SQL tuples. * @type string $on_duplicate Default ON DUPLICATE KEY clause. * } * @param Post_Views_Counter_Import $importer Import handler instance. */ $query = apply_filters( 'pvc_import_provider_query', $query, [ 'strategy' => sanitize_key( $strategy ), 'provider' => $provider, 'sql_parts' => $sql_parts, 'on_duplicate' => $on_duplicate ], $this ); if ( $query === false ) { return false; } return $wpdb->query( $query ); } /** * Adjust import statistics to include skipped totals information. * * @param array $stats * @param array $totals_map * @param string $strategy * @return void */ private function apply_skip_statistics( &$stats, $totals_map, $strategy ) { if ( empty( $stats ) || empty( $totals_map ) ) { return; } $skip_stats = $this->calculate_total_skip_stats( $totals_map, $strategy ); if ( empty( $skip_stats ) ) { return; } $stats['skipped'] = $skip_stats; if ( isset( $stats['total_views'] ) ) { $stats['total_views'] = max( 0, (int) $stats['total_views'] - $skip_stats['views'] ); } if ( isset( $stats['posts_processed'] ) ) { $stats['posts_processed'] = max( 0, (int) $stats['posts_processed'] - $skip_stats['posts'] ); } } /** * Calculate how many totals will be skipped by the given strategy. * * @param array $totals_map Array of post_id => total_count. * @param string $strategy * @return array */ private function calculate_total_skip_stats( $totals_map, $strategy ) { $strategy = sanitize_key( $strategy ); $advanced_strategies = [ 'skip_existing', 'keep_higher_count', 'fill_empty_only' ]; if ( empty( $totals_map ) || ! in_array( $strategy, $advanced_strategies, true ) ) { return []; } $existing = $this->get_existing_total_counts( array_keys( $totals_map ) ); $skipped_views = 0; $skipped_posts = 0; foreach ( $totals_map as $post_id => $value ) { $current = isset( $existing[ $post_id ] ) ? (int) $existing[ $post_id ] : null; $skip = false; if ( $strategy === 'skip_existing' && $current !== null ) { $skip = true; } elseif ( $strategy === 'keep_higher_count' && $current !== null && $current >= $value ) { $skip = true; } elseif ( $strategy === 'fill_empty_only' && $current !== null && $current > 0 ) { $skip = true; } if ( $skip ) { $skipped_views += (int) $value; $skipped_posts++; } } if ( $skipped_posts === 0 ) { return []; } return [ 'views' => $skipped_views, 'posts' => $skipped_posts ]; } /** * Get existing total counts for selected posts. * * @param array $post_ids * @return array */ private function get_existing_total_counts( $post_ids ) { global $wpdb; $post_ids = array_filter( array_map( 'intval', (array) $post_ids ) ); $post_ids = array_values( array_unique( $post_ids ) ); if ( empty( $post_ids ) ) { return []; } $existing = []; foreach ( array_chunk( $post_ids, 500 ) as $chunk ) { $placeholders = implode( ',', array_fill( 0, count( $chunk ), '%d' ) ); $sql = $wpdb->prepare( "SELECT id, count FROM {$wpdb->prefix}post_views WHERE type = 4 AND period = 'total' AND id IN ({$placeholders})", $chunk ); $rows = $wpdb->get_results( $sql, ARRAY_A ); foreach ( (array) $rows as $row ) { $existing[ (int) $row['id'] ] = (int) $row['count']; } } return $existing; } /** * Generate import/analyze message with statistics. * * @param array $stats Import statistics * @param string $mode Mode: 'import' or 'analyze' * @return string */ private function generate_import_message( $stats, $mode = 'import' ) { $message_parts = []; $source_label = ''; if ( ! empty( $stats['source'] ) ) { $source_label = $stats['source']; } if ( $source_label !== '' ) { if ( $mode === 'analyze' ) { $message_parts[] = sprintf( __( 'Analysis of %s:', 'post-views-counter' ), $source_label ); } else { $message_parts[] = sprintf( __( 'Import from %s:', 'post-views-counter' ), $source_label ); } } // main success message if ( isset( $stats['total_views'] ) && isset( $stats['posts_processed'] ) ) { if ( $mode === 'analyze' ) { $message_parts[] = sprintf( __( 'Found %s total views for %s posts.', 'post-views-counter' ), number_format_i18n( $stats['total_views'] ), number_format_i18n( $stats['posts_processed'] ) ); } else { $message_parts[] = sprintf( __( 'Successfully imported %s total views for %s posts.', 'post-views-counter' ), number_format_i18n( $stats['total_views'] ), number_format_i18n( $stats['posts_processed'] ) ); } } // additional info (like skipped URLs) if ( ! empty( $stats['additional_info'] ) ) { $message_parts[] = $stats['additional_info']; } if ( isset( $stats['skipped']['views'], $stats['skipped']['posts'] ) ) { $message_parts[] = sprintf( __( 'Skipped %1$s total views for %2$s posts.', 'post-views-counter' ), number_format_i18n( $stats['skipped']['views'] ), number_format_i18n( $stats['skipped']['posts'] ) ); } return implode( ' ', $message_parts ); } /** * Map provider target URL to content data. * * @param string $target * @param array $tracked_post_types * @param string $provider * @return array */ private function map_target_to_content( $target, $tracked_post_types, $provider ) { $content = [ 'content_type' => 'post', 'content_id' => $this->map_target_to_post_id( $target, $tracked_post_types ) ]; /** * Filter provider content mapping so it's possible to process non-post URLs. * * @since 1.5.10 * * @param array $content { * @type string $content_type Resolved content type. * @type int $content_id Target identifier. * } * @param string $target Target path recorded by the provider. * @param string $provider Current import provider slug. * @param array $tracked_post_types Allowed post types for PVC. * @param Post_Views_Counter_Import $importer Import handler instance. */ return apply_filters( 'pvc_import_map_target_to_content', $content, $target, $provider, $tracked_post_types, $this ); } /** * Map Statify target URL to post ID. * * @param string $target * @param array $tracked_post_types * @return int */ private function map_target_to_post_id( $target, $tracked_post_types ) { // handle empty tracked post types if ( empty( $tracked_post_types ) ) { return 0; } // handle homepage if ( $target === '/' ) { $post_id = get_option( 'page_on_front' ); if ( $post_id && in_array( get_post_type( $post_id ), $tracked_post_types, true ) ) { return (int) $post_id; } } // build full URL from relative target path $url = home_url( $target ); $post_id = url_to_postid( $url ); // verify post exists and is a tracked type if ( $post_id ) { $post_type = get_post_type( $post_id ); if ( $post_type && in_array( $post_type, $tracked_post_types, true ) ) { return (int) $post_id; } } return 0; } /** * Flush caches specific to Post Views Counter. * * @return void */ private function flush_pvc_caches() { global $wp_object_cache; if ( ! is_object( $wp_object_cache ) || ! property_exists( $wp_object_cache, 'cache' ) ) { return; } $groups = [ 'pvc', 'pvc-get_post_views', 'pvc-get_views' ]; foreach ( $groups as $group ) { if ( empty( $wp_object_cache->cache[$group] ) || ! is_array( $wp_object_cache->cache[$group] ) ) { continue; } foreach ( array_keys( $wp_object_cache->cache[$group] ) as $key ) { wp_cache_delete( $key, $group ); } } } /** * Retrieve the human readable label for a provider. * * @param string $slug * @return string */ private function get_provider_label( $slug ) { if ( isset( $this->import_provider_labels[ $slug ] ) ) { return $this->import_provider_labels[ $slug ]; } return ucwords( str_replace( '_', ' ', $slug ) ); } /** * Build period keys for a timestamp. * * @param int $timestamp * @param bool $use_gmt * @return array */ private function get_period_keys_from_timestamp( $timestamp, $use_gmt ) { $date = $use_gmt ? gmdate( 'W-d-m-Y-o', $timestamp ) : date( 'W-d-m-Y-o', $timestamp ); $parts = explode( '-', $date ); return [ 'day' => $parts[3] . $parts[2] . $parts[1], 'week' => $parts[4] . $parts[0], 'month' => $parts[3] . $parts[2], 'year' => $parts[3] ]; } }